#ifndef _CIRCULARBUFFER_CPP_INCLUDED
#define _CIRCULARBUFFER_CPP_INCLUDED

#include "CircularBuffer.h"
#include <stdlib.h>


//////////////////////////////
//
// CircularBuffer::CircularBuffer -- Constructor.
//

template<class type>
CircularBuffer<type>::CircularBuffer(void) {
    size = 0;
    buffer = NULL;
    reset();
}

template<class type>
CircularBuffer<type>::CircularBuffer(int maxElements) {
    if (maxElements < 0) {
        printf("Error: cannot have a negative number of elements: ");
        exit(1);
    }
    if (maxElements == 0) {
        size = 0;
        buffer = NULL;
        reset();
    } else {
        size = maxElements;
        buffer = new type[maxElements];
        reset();
    }
}

template<class type>
CircularBuffer<type>::CircularBuffer(const CircularBuffer<type>& anotherBuffer) {
    size = anotherBuffer.size;
    if (getSize() == 0) {
        buffer = NULL;
        reset();
    } else {
        buffer = new type[getSize()];
        writeIndex = anotherBuffer.writeIndex;
        readIndex = anotherBuffer.readIndex;
        itemCount = anotherBuffer.itemCount;
        for (int i = 0; i < getSize(); i++) {
            buffer[i] = anotherBuffer.buffer[i];
        }
    }
}



//////////////////////////////
//
// CircularBuffer::~CircularBuffer -- Destructor.
//    deallocates buffer memory.
//

template<class type>
CircularBuffer<type>::~CircularBuffer() {
    if (buffer != NULL) {
        delete [] buffer;
    }
}



//////////////////////////////
//
// CircularBuffer::getCount -- returns the number of elements
//    between the write index and the read index.
//

template<class type>
int CircularBuffer<type>::getCount(void) const {
    return itemCount;
}



//////////////////////////////
//
// CircularBuffer::getSize -- returns the allocated size of the buffer.
//

template<class type>
int CircularBuffer<type>::getSize(void) const {
    return size;
}



//////////////////////////////
//
// CircularBuffer::insert -- add an element to the circular buffer
//

template<class type>
void CircularBuffer<type>::insert(const type& anItem) {
    itemCount == getSize() ? : itemCount++;
    increment(writeIndex);
    readIndex = writeIndex;
    //printf("writeIndex: %d ReadIndex: %d Itemcount: %d\n",writeIndex,readIndex,itemCount);
    buffer[writeIndex] = anItem;
    //printf("Inseri o dado: %f\n",anItem);
}


//////////////////////////////
//
// CircularBuffer::getArray -- Extract the data array
//

template<class type>
type* CircularBuffer<type>::getArray(int n,int &size) {
    float valor_aux;
    size = itemCount;
    int aux1 = readIndex;
    int aux2 = writeIndex;
    readIndex = writeIndex;
    //type* buffer_aux = (type*) malloc (sizeof(type)*itemCount);
    type* buffer_aux = new type[itemCount];
    if (n==0)
        n = itemCount;
    for (int i = 0; ((i < itemCount)&&(i<n)); i++) {
        valor_aux     = read();
        buffer_aux[i] = valor_aux;
        //printf("buffer_aux[%d] = %f - ItemCount: %d - readindex: %d writeindex: %d \n",i,valor_aux,itemCount,readIndex,writeIndex);
    }
    readIndex = aux1;
    writeIndex = aux2;
    return buffer_aux;
}


//////////////////////////////
//
// CircularBuffer::print -- Print the data array
//

template<class type>
void CircularBuffer<type>::print(void) {
    readIndex = writeIndex;
    for (int i = 0; i <= itemCount; i++)
        printf("Dado: %f\n",read());
}



//////////////////////////////
//
// CircularBuffer::read -- an alias for the extract function.
//

template<class type>
type CircularBuffer<type>::read(void) {
    if (itemCount < 0) {
        printf("Error: no elements in buffer to extract.");
        exit(1);
    }
    type aux = buffer[readIndex];
    decrement(readIndex);
    return aux;
}



//////////////////////////////
//
// CircularBuffer::reset -- throws out all previous data and
//    sets the read/write/count to initial values.  The size
//    data variable must be valid before this function is
//    called.
//

template<class type>
void CircularBuffer<type>::reset(void) {
    readIndex = writeIndex = getSize() - 1;
    itemCount = 0;
}



///////////////////////////////////////////////////////////////////////////
//
// private functions
//

//////////////////////////////
//
// CircularBuffer::increment -- adds one to specified index and
//    will automatically wrap the index when it gets too large.
//

template<class type>
void CircularBuffer<type>::increment(int& index) {
    index++;
    if (index >= getSize()) {
        index = 0;
    }
}

//////////////////////////////
//
// CircularBuffer::decrement -- adds one to specified index and
//    will automatically wrap the index when it gets too large.
//

template<class type>
void CircularBuffer<type>::decrement(int& index) {
    index--;
    if (index < 0) {
        index = getSize() - 1;
    }
}


#endif  /* _CIRCULARBUFFER_CPP_INCLUDED */

